package cn.conac.rc.framework.utils;

import java.io.File;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.Writer;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import freemarker.template.Configuration;
import freemarker.template.Template;

/**
 * 公共entity、service、repository自动生成工具带注解（关联关系需要手动添加）</br>
 * 执行前请确认 </br>
 * 1、db链接是否正确</br>
 * 2、tablename的填写 </br>
 * 3、package基本路径 </br>
 * 确认以上三步后，致敬运行此java，执行后 生成的文件在output目录，将文件拷贝到已经创建好的资源文件目录中。
 * @author haocm
 */
public class AutoCreator {

	// DB等相关常量
	private static String dbConfig = "/config.properties";
	private static char UNDERLINE = '_';
	//private static String DATA_TABLE = "1";
	//private static String BASE_TABLE = "2";
	//private static String tableType = "";// 数据库表类别（区分Entity类的继承类）
	// FreeMarker相关配置
	private static Configuration configuration;
	private static Template template;
	private static Writer writer;
	// FreeMarker模板相关常量
	private static String FTLS_PATH = "./ftls";
	private static String FTLS_BEAN_TEMPLATE = "beanTemplate.ftl";
	private static String FTLS_VO_TEMPLATE = "voTemplate.ftl";
	private static String FTLS_REPOSITORY_TEMPLATE = "repositoryTemplate.ftl";
	private static String FTLS_SERVICE_TEMPLATE = "serviceTemplate.ftl";
	private static String FTLS_CONTROLLER_TEMPLATE = "controllerTemplate.ftl";
    // 包名，版本
    private static String packageStr = "cn.conac.rc.share";
    private static String versionStr = "1.0";
    // 根目录，输出目录
    private static String rootpath = System.getProperty("user.dir");
    private static String output = "/output/";
    
    /**
     * main函数
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
    	
    	// 创建DB链接信息，获取数据库表名信息
        Connection conn = null;
    	Properties props = new Properties();
    	InputStream in = ClassLoader.class.getResourceAsStream(dbConfig);
    	props.load(in);
        Class.forName(props.getProperty("driver"));
        conn = DriverManager.getConnection(props.getProperty("url"),props);
        in.close();

        String tableNas = props.getProperty("tableNames");
        List<String> tableNames = new ArrayList<String>();
        // 获取全部表
        if(tableNas == null || "".equals(tableNas)){
    		System.out.println(" ++++++++++++++++指定数据库全表输出+++++++++++++++");
    		
        	String database = props.getProperty("url");
        	String userName = props.getProperty("user");
        	int startIndex = database.lastIndexOf(":");
        	String databaseName = database.substring(startIndex+1, database.length());
        	DatabaseMetaData dbmd = conn.getMetaData();
        	ResultSet rest = dbmd.getTables(databaseName, null, null, new String[] { "TABLE" });
        	// 输出 table_name
        	while (rest.next()) {
        		String tableSchem = rest.getString("TABLE_SCHEM");  
        		if (userName.equalsIgnoreCase(tableSchem)) {
        			tableNames.add(rest.getString("TABLE_NAME"));
        		}
        	}
        // 指定表
        } else {
    		System.out.println(" ++++++++++++++++指定表输出:" + tableNas + "+++++++++++++++");

        	String[] tables = tableNas.split(",");
        	for(String table:tables){
        		tableNames.add(table);
        	}
        }

		System.out.println("\r\n =============Entity类输出开始!================");
        beanCreateFunction(conn, tableNames);
		
		System.out.println("\r\n =============Repository类输出开始!================");
        repositoryCreateFunction(tableNames);
		
		System.out.println("\r\n =============vo类输出开始!================");
        voCreateFunction(tableNames);
		
		System.out.println("\r\n =============Service类输出开始!================");
        serviceCreateFunction(tableNames);
		
		System.out.println("\r\n =============Controller类输出开始!================");
        controllerCreateFunction(tableNames);
    }

    /**
     * Entity类输入用方法
     * @throws Exception
     */
    public static void beanCreateFunction(Connection conn,List<String> tableNames) throws Exception {
        
        // 创建Freemarker配置实例
        configuration = new Configuration();
        configuration.setDirectoryForTemplateLoading(new File(FTLS_PATH));

        for (String tablename : tableNames) {
            try{
                DatabaseMetaData dbmd = conn.getMetaData();
                ResultSet rs = dbmd.getColumns(null, getSchema(conn), tablename.toUpperCase(), "%");

                BeanCreator beanCreator = new BeanCreator();
                List<Field> fieldList = new ArrayList<Field>();
            	//tableType = BASE_TABLE;
                while (rs.next()) {
                	/*// 判断数据库表类别
                	if("DELETE_MARK".equals(rs.getString("COLUMN_NAME"))){
                		tableType = DATA_TABLE;
            		}
                	// 过滤常用字段
                	if(removeNormalColumn(rs.getString("COLUMN_NAME"))){
                		continue;
                	}*/

                    Field field = new Field();
                    // 字段名称
                    field.setName(underlineToCamel(rs.getString("COLUMN_NAME").toLowerCase()));
                    // 字段类型
                    field.setType(sqlType2JavaType(rs.getString("TYPE_NAME")));
                    // 字段注释
                    field.setComment(rs.getString("REMARKS"));

                    fieldList.add(field);
                }
                beanCreator.setTableName(tablename);
                beanCreator.setClassName(underlineToCamel(removeTableNameHeader(tablename).toLowerCase()));
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                beanCreator.setDate(simpleDateFormat.format(new Date()));
                beanCreator.setFieldList(fieldList);
                beanCreator.setPackageName(packageStr);
                beanCreator.setVersion(versionStr);
                //beanCreator.setTableType(tableType);
                beanCreator.setSerialVersionUID("" + System.currentTimeMillis() + Math.round(Math.random()*1000000));
                
                Map<String, Object> rootMap = new HashMap<String, Object>();
                rootMap.put("beanCreator", beanCreator);
                
                // entity文件名
                String entityName = initcap(underlineToCamel(removeTableNameHeader(tablename).toLowerCase())) + "Entity.java";
                // entity路径
        		String entityPath = rootpath + output + packageStr.replace(".", "/") + "/entity/";
        		
        		File filePath = new File(entityPath);
        		if (!filePath.exists()) {
        			filePath.mkdirs();
        		}
        		
        		File file = new File(entityPath + entityName);
        		if (!file.exists()) {
        			file.createNewFile();
        		}

        		template = configuration.getTemplate(FTLS_BEAN_TEMPLATE);
                writer = new FileWriter(file);
                template.process(rootMap, writer);
                writer.flush();
        		writer.close();
        		
        		System.out.println(entityName + "输出完毕!");

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * repository类输入用方法
     * @throws Exception
     */
    public static void repositoryCreateFunction(List<String> tableNames) throws Exception {
        // 创建Freemarker配置实例
        configuration = new Configuration();
        configuration.setDirectoryForTemplateLoading(new File(FTLS_PATH));
        
        for (String tablename : tableNames) {
        	RepositoryCreator repositoryCreator = new RepositoryCreator();
        	
        	repositoryCreator.setClassName(underlineToCamel(removeTableNameHeader(tablename).toLowerCase()));
        	SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        	repositoryCreator.setDate(simpleDateFormat.format(new Date()));
        	repositoryCreator.setPackageName(packageStr);
        	repositoryCreator.setVersion(versionStr);
        	
            Map<String, Object> rootMap = new HashMap<String, Object>();
            rootMap.put("repositoryCreator", repositoryCreator);
        	
            // repository文件名
            String repositoryName = initcap(underlineToCamel(removeTableNameHeader(tablename).toLowerCase())) + "Repository.java";
        	// repository路径
    		String repositoryPath = rootpath + output + packageStr.replace(".", "/") + "/repository/";

    		File filePath = new File(repositoryPath);
    		if (!filePath.exists()) {
    			filePath.mkdirs();
    		}
    		
    		File file = new File(repositoryPath + repositoryName);
    		if (!file.exists()) {
    			file.createNewFile();
    		}

    		template = configuration.getTemplate(FTLS_REPOSITORY_TEMPLATE);
            writer = new FileWriter(file);
            template.process(rootMap, writer);
            writer.flush();
    		writer.close();
    		
    		System.out.println(repositoryName + "输出完毕!");
        }
    }

    /**
     * VO类输入用方法
     * @throws Exception
     */
    public static void voCreateFunction(List<String> tableNames) throws Exception {
        // 创建Freemarker配置实例
        configuration = new Configuration();
        configuration.setDirectoryForTemplateLoading(new File(FTLS_PATH));
        
        for (String tablename : tableNames) {
        	VoCreator creator = new VoCreator();
        	
        	creator.setClassName(underlineToCamel(removeTableNameHeader(tablename).toLowerCase()));
        	SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        	creator.setDate(simpleDateFormat.format(new Date()));
        	creator.setPackageName(packageStr);
        	creator.setVersion(versionStr);
            creator.setSerialVersionUID("" + System.currentTimeMillis() + Math.round(Math.random()*1000000));
        	
            Map<String, Object> rootMap = new HashMap<String, Object>();
            rootMap.put("voCreator", creator);

            // vo文件名
            String voName = initcap(underlineToCamel(removeTableNameHeader(tablename).toLowerCase())) + "Vo.java";
        	// vo文件路劲
    		String voPath = rootpath + output + packageStr.replace(".", "/") + "/vo/";
    		
    		File filePath = new File(voPath);
    		if (!filePath.exists()) {
    			filePath.mkdirs();
    		}
    		
    		File file = new File(voPath + voName);
    		if (!file.exists()) {
    			file.createNewFile();
    		}

    		template = configuration.getTemplate(FTLS_VO_TEMPLATE);
            writer = new FileWriter(file);
            template.process(rootMap, writer);
            writer.flush();
    		writer.close();
    		
    		System.out.println(voName + "输出完毕!");
        }
    }

    /**
     * Service类输入用方法
     * @throws Exception
     */
    public static void serviceCreateFunction(List<String> tableNames) throws Exception {
        // 创建Freemarker配置实例
        configuration = new Configuration();
        configuration.setDirectoryForTemplateLoading(new File(FTLS_PATH));
        
        for(String tablename : tableNames) {
        	ServiceCreator creator = new ServiceCreator();
        	
        	creator.setClassName(underlineToCamel(removeTableNameHeader(tablename).toLowerCase()));
        	SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        	creator.setDate(simpleDateFormat.format(new Date()));
        	creator.setPackageName(packageStr);
        	creator.setVersion(versionStr);
        	
            Map<String, Object> rootMap = new HashMap<String, Object>();
            rootMap.put("serviceCreator", creator);

            // service文件名
            String serviceName = initcap(underlineToCamel(removeTableNameHeader(tablename).toLowerCase())) + "Service.java";
        	// service文件路劲
    		String servicePath = rootpath + output + packageStr.replace(".", "/") + "/service/";
    		
    		File filePath = new File(servicePath);
    		if (!filePath.exists()) {
    			filePath.mkdirs();
    		}
    		
    		File file = new File(servicePath + serviceName);
    		if (!file.exists()) {
    			file.createNewFile();
    		}

    		template = configuration.getTemplate(FTLS_SERVICE_TEMPLATE);
            writer = new FileWriter(file);
            template.process(rootMap, writer);
            writer.flush();
    		writer.close();
    		
    		System.out.println(serviceName + "输出完毕!");
        }
    }

    /**
     * Controller类输入用方法
     * @throws Exception
     */
    public static void controllerCreateFunction(List<String> tableNames) throws Exception {
        // 创建Freemarker配置实例
        configuration = new Configuration();
        configuration.setDirectoryForTemplateLoading(new File(FTLS_PATH));
        
        for(String tablename : tableNames) {
        	ControllerCreator creator = new ControllerCreator();
        	
        	creator.setClassName(underlineToCamel(removeTableNameHeader(tablename).toLowerCase()));
        	SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        	creator.setDate(simpleDateFormat.format(new Date()));
        	creator.setPackageName(packageStr);
        	creator.setVersion(versionStr);
        	
            Map<String, Object> rootMap = new HashMap<String, Object>();
            rootMap.put("controllerCreator", creator);

            // controller文件名
            String controllerName = initcap(underlineToCamel(removeTableNameHeader(tablename).toLowerCase())) + "Controller.java";
        	// controller文件路劲
    		String controllerPath = rootpath + output + packageStr.replace(".", "/") + "/rest/";
    		
    		File filePath = new File(controllerPath);
    		if (!filePath.exists()) {
    			filePath.mkdirs();
    		}
    		
    		File file = new File(controllerPath + controllerName);
    		if (!file.exists()) {
    			file.createNewFile();
    		}

    		template = configuration.getTemplate(FTLS_CONTROLLER_TEMPLATE);
            writer = new FileWriter(file);
            template.process(rootMap, writer);
            writer.flush();
    		writer.close();
    		
    		System.out.println(controllerName + "输出完毕!");
        }
    }

//    /**
//     * 将常用字段（ID,CreateUser,UpdateUser等）过滤掉
//     * @param column
//     * @return boolean 
//     */
//    private static boolean removeNormalColumn(String column){
//		if("ID".equals(column)
//				|| "CREATE_USER".equals(column)
//				|| "CREATE_DATE".equals(column)
//				|| "UPDATE_USER".equals(column)
//				|| "UPDATE_DATE".equals(column)
//				|| "DELETE_MARK".equals(column)
//				|| "REMARKS".equals(column)){
//			return true;
//		}
//		return false;
//	}
    
    /**
     * 获取Schema
     * @param conn
     * @return
     * @throws Exception
     */
    private static String getSchema(Connection conn) throws Exception {
        String schema;
        schema = conn.getMetaData().getUserName();
        if ((schema == null) || (schema.length() == 0)) {
            throw new Exception("ORACLE数据库模式不允许为空");
        }
        return schema.toUpperCase().toString();
    }

    /**
     * 把输入字符串的首字母改成大写
     * @param str
     * @return
     */
    private static String initcap(String str) {
        char[] ch = str.toCharArray();
        if (ch[0] >= 'a' && ch[0] <= 'z') {
            ch[0] = (char) (ch[0] - 32);
        }
        return new String(ch);
    }

    private static String sqlType2JavaType(String sqlType) {
        if (sqlType.equalsIgnoreCase("tinyint")) {
            return "Integer";
        } else if (sqlType.equalsIgnoreCase("smallint")) {
            return "Integer";
        } else if (sqlType.equalsIgnoreCase("int") || sqlType.equalsIgnoreCase("NUMBER")) {
            return "Integer";
        } else if (sqlType.equalsIgnoreCase("bigint")) {
            return "Long";
        } else if (sqlType.equalsIgnoreCase("float")) {
            return "float";
        } else if (sqlType.equalsIgnoreCase("decimal") || sqlType.equalsIgnoreCase("numeric")
                || sqlType.equalsIgnoreCase("real")) {
            return "Double";
        } else if (sqlType.equalsIgnoreCase("money") || sqlType.equalsIgnoreCase("smallmoney")) {
            return "Double";
        } else if (sqlType.equalsIgnoreCase("varchar") || sqlType.equalsIgnoreCase("char")
                || sqlType.equalsIgnoreCase("nvarchar") || sqlType.equalsIgnoreCase("nvarchar2")
                || sqlType.equalsIgnoreCase("VARCHAR2") || sqlType.equalsIgnoreCase("nchar")
                || sqlType.equalsIgnoreCase("clob") || sqlType.equalsIgnoreCase("RAW")) {
            return "String";
        } else if (sqlType.equalsIgnoreCase("datetime") || sqlType.equalsIgnoreCase("timestamp")
                || sqlType.equalsIgnoreCase("DATE") || sqlType.equalsIgnoreCase("timestamp(6)")) {
            return "Date";
        }

        return null;
    }

    /**
     * 下划线转驼峰
     * @param param
     * @return
     */
    private static String underlineToCamel(String param) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (c == UNDERLINE) {
                if (++i < len) {
                    sb.append(Character.toUpperCase(param.charAt(i)));
                }
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 去除表名字开头
     * @param param
     * @return
     */
    private static String removeTableNameHeader(String param){
    	String rtl = param;
    	if(param.startsWith("OFS_") || param.startsWith("ICP_") || param.startsWith("RCO_")
    			//|| param.startsWith("AEL_") || param.startsWith("DEL_") || param.startsWith("AEM_")
    			//|| param.startsWith("ACT_") || param.startsWith("DEX_") || param.startsWith("OSS_")
    			|| param.startsWith("RCA_") || param.startsWith("RCD_")){
    		rtl = param.substring(4);
    	} else if(param.startsWith("ICPO_")){
    		rtl = param.substring(5);
    	}
    	return rtl;
    }
}